package per.dg.digital_klotski;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.DigitalClock;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import androidx.lifecycle.ViewModelProvider;

import per.dg.digital_klotski.utils.FontDisplayUtil;
import per.dg.digital_klotski.views.DigitalKlotskiChildView;
import per.dg.digital_klotski.views.DigitalKlotskiManager;

public class DigitalKlotskiViewGroup extends ViewGroup {

    private Context mContext;

    int[][] data;

    View[][] views;

    DigitalKlotskiManager digitalKlotskiManager;

    private int spac = 9;

    private int marginleft = 10;

    private int width;

    private int height;

    private int col_0;

    private int row_0;

    Typeface typeface;

    float startX, startY;

    int minMoveDisparity;

    public void setSpac(int spac) {
        this.spac = spac;
        initData();

        removeAllViews();
        invalidate();
        forceLayout();
        requestLayout();
    }

    public DigitalKlotskiViewGroup(Context context) {
        this(context, null);
    }

    public DigitalKlotskiViewGroup(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DigitalKlotskiViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.mContext = context;

        initData();
    }

    private void initData() {
        typeface =Typeface.createFromAsset(mContext.getAssets(),"fonts/ALIBABA-PUHUITI-HEAVY.TTF");

        digitalKlotskiManager = new DigitalKlotskiManager();
        digitalKlotskiManager.setCol(spac);
        digitalKlotskiManager.setRow(spac);
        data = digitalKlotskiManager.getData();

        views = new View[spac][spac];

        minMoveDisparity = FontDisplayUtil.dip2px(getContext(), 50);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        width = measure(widthMeasureSpec);
        height = measure(heightMeasureSpec);
        width = height = width > height ? height : width;
        setMeasuredDimension(width, height);
    }

    private int measure(int measureSpace){
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpace);
        int specSize = MeasureSpec.getSize(measureSpace);
        if(specMode == MeasureSpec.EXACTLY) {
            //精确值模式
            result = specSize;
        }else if(specMode == MeasureSpec.AT_MOST) {
            //最大值模式
//            result = minSpac;
            result = width;
            result = Math.min(result,specSize);
        }

        return result;
    }

    @Override
    protected void onLayout(final boolean changed, int l, int t, int r, int b) {
//        final int childWidth = (width - marginleft * (spac + 1)) / spac;
        final int childWidth = (width - getPaddingLeft() - getPaddingRight()) / spac;
        Log.e("onLayout: ", childWidth+"");
        Log.e("onLayout: ", l+":"+t+":"+r+":"+b);
        if(views[0][0] == null){
            for(int i = 0; i < spac; i++){
                for(int j = 0; j < spac; j++){

                    if(data[j][i] == 0){
                        col_0 = j;
                        row_0 = i;
                    }

//                LinearLayout relativeLayout = new LinearLayout(mContext);
//                relativeLayout.setLayoutParams(new LinearLayout.LayoutParams(childWidth, childWidth));
//                relativeLayout.setBackground(getResources().getDrawable(R.mipmap.box));
//                relativeLayout.setTag(new int[]{j, i});

//                TextView tv;
                    DigitalKlotskiChildView tv;
//                tv = new TextView(mContext);
                    tv = new DigitalKlotskiChildView(mContext);
                    ViewGroup.LayoutParams layoutParams;
                    layoutParams = new ViewGroup.LayoutParams(childWidth, childWidth);
                    tv.setLayoutParams(layoutParams);
                    tv.setText(data[j][i]+"");
//                tv.setTextColor(getResources().getColor(R.color.colorAccent));
//                tv.setTypeface(typeface);
                    tv.setBackground(getResources().getDrawable(R.mipmap.box));
                    tv.setTag(new int[]{j, i});
//                tv.setGravity(Gravity.CENTER);
                    tv.setTextSize((int) (childWidth/2));


//                relativeLayout.addView(tv);

                    addView(tv);

                    views[j][i] = tv;

                    tv.layout(j *childWidth+getPaddingLeft(), i * childWidth+getPaddingTop(), (j+1) *(childWidth)+getPaddingLeft(), (i+1) * (childWidth)+getPaddingTop());
//tv.setGravity(Gravity.CENTER);
                    if(data[j][i] == 0){
                        tv.setVisibility(View.INVISIBLE);
                        tv.setBackground(null);
                        tv.setText("");
                    }

                    tv.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            if(mDigitalKlotskiChange != null){
                                mDigitalKlotskiChange.onChildViewClick();
                            }
                            int[] ints = (int[]) v.getTag();
                            int x = 0, y = 0;
                            int col = ints[0];
                            int row = ints[1];
                            changeDataAndViews(v, row, col, childWidth);


//                            Log.e("onClick: ", v.getWidth()+"");
                        }
                    });

                    tv.setOnTouchListener(new OnTouchListener() {
                        @Override
                        public boolean onTouch(View v, MotionEvent event) {
                            int pointCount = event.getPointerCount();
                            switch (pointCount) {
                                case 1:
                                    switch (event.getAction() & MotionEvent.ACTION_MASK) {
                                        case MotionEvent.ACTION_DOWN:
                                            if(mDigitalKlotskiChange != null){
                                                mDigitalKlotskiChange.onChildViewClick();
                                            }
                                            startX = event.getX();
                                            startY = event.getY();
                                            Log.e("touch", "1 down-------");
                                            break;
                                        case MotionEvent.ACTION_MOVE:
                                            Log.e("touch", "1 move-------");
                                            break;
                                        case MotionEvent.ACTION_UP:
                                            Log.e("touch", "1 up-------");
                                            int[] ints = (int[]) v.getTag();
                                            int x = 0, y = 0;
                                            int col = ints[0];
                                            int row = ints[1];
                                            float tempX = event.getX();
                                            float tempY = event.getY();
                                            float disparityX = tempX - startX;
                                            float disparityY = tempY - startY;
                                            float disparityX2 = Math.abs(disparityX);
                                            float disparityY2 = Math.abs(disparityY);
                                            if(disparityX2 > minMoveDisparity || disparityY2 > minMoveDisparity){
                                                if(disparityX2 > disparityY2){
                                                    if(disparityY2 < childWidth){
                                                        if(disparityX > 0){
                                                            touch(v, row, col, childWidth, 1);
                                                        }else {
                                                            touch(v, row, col, childWidth, 0);
                                                        }
                                                        return true;
                                                    }
                                                }else {
                                                    if(disparityX2 < childWidth){
                                                        if(disparityY > 0){
                                                            touch(v, row, col, childWidth, 3);
                                                        }else {
                                                            touch(v, row, col, childWidth, 2);
                                                        }
                                                        return true;
                                                    }
                                                }
                                            }
                                    }
                                    break;
                                case 2:
                                    switch (event.getAction() & MotionEvent.ACTION_MASK) {
                                        case MotionEvent.ACTION_POINTER_DOWN:
                                            Log.e("touch", "2 down-------");
                                            break;
                                        case MotionEvent.ACTION_MOVE:
                                            Log.e("touch", "2 move-------");
                                            break;
                                        case MotionEvent.ACTION_POINTER_UP:
                                            Log.e("touch", "2 up-------");
                                            break;
                                    }
                                    break;
                                case 3:
                                    switch (event.getAction() & MotionEvent.ACTION_MASK) {
                                        case MotionEvent.ACTION_POINTER_DOWN:
                                            Log.e("touch", "3 down-------");
                                            break;
                                        case MotionEvent.ACTION_MOVE:
                                            Log.e("touch", "3 move-------");
                                            break;
                                        case MotionEvent.ACTION_POINTER_UP:
                                            Log.e("touch", "3 up-------");
                                            break;
                                    }
                                    break;
                            }
                            return false;
                        }
                    });
                }
            }
        }
    }

    private void setenabled(boolean b) {
        if(views[0][0] != null){
            for(View[] view : views){
                for(View viewChild : view){
                    viewChild.setEnabled(false);
                }
            }
        }
    }

    /**
     *
     * @param v
     * @param row
     * @param col
     * @param childWidth
     * @param direction 0 : 向左滑动  1 ：向右滑动 2：向上滑动 3：向下滑动
     */
    private void touch(View v, int row, int col, int childWidth, int direction){
        boolean canMove = false;
        switch (direction){
            case 0:
                if(row == row_0 && col_0 < col){
                    canMove = true;
                }
                break;
            case 1:
                if(row == row_0 && col_0 > col){
                    canMove = true;
                }
                break;
            case 2:
                if(col_0 == col && row > row_0){
                    canMove = true;
                }
                break;
            case 3:
                if(col_0 == col && row < row_0){
                    canMove = true;
                }
                break;
        }
        if(canMove){
            changeDataAndViews(v, row, col, childWidth);
        }
    }

    private void changeDataAndViews(View v, int row, int col, int childWidth){
        int x = 0, y = 0;
        if(row == row_0){
            if(col - col_0 > 0){
                x = -childWidth;
                int temp = data[col_0][row_0];
                View viewTemp = views[col_0][row_0];
                for(int i = col_0; i < col; i++){
                    data[i][row] = data[i+1][row];
                    views[i][row] = views[i+1][row];
                    views[i][row].offsetLeftAndRight(x);
                    views[i][row].setTag(new int[]{i, row});
                }
                data[col][row] = temp;
                views[col][row] = viewTemp;
                views[col][row].setTag(new int[]{col, row});
                views[col][row].offsetLeftAndRight(-(x*(col - col_0)));
                views[col][row].setVisibility(INVISIBLE);
                col_0 = col;
            }else if(col - col_0 < 0) {
                x = childWidth;
                int temp = data[col_0][row_0];
                View viewTemp = views[col_0][row_0];
                for(int i = col_0; i > col; i--){
                    data[i][row] = data[i-1][row];
                    views[i][row] = views[i-1][row];
                    views[i][row].offsetLeftAndRight(x);
                    views[i][row].setTag(new int[]{i, row});
                }
                data[col][row] = temp;
                views[col][row] = viewTemp;
                views[col][row].setTag(new int[]{col, row});
                views[col][row].offsetLeftAndRight(-(x*(col_0 - col)));
                views[col][row].setVisibility(INVISIBLE);
                col_0 = col;
            }
            views[col][row].setBackground(null);
        }else if(col == col_0){
            if(row - row_0 > 0){
                y = -childWidth;
                int temp = data[col_0][row_0];
                View viewTemp = views[col_0][row_0];
                for(int i = row_0; i < row; i++){
                    data[col][i] = data[col][i+1];
                    views[col][i] = views[col][i+1];
                    views[col][i].offsetTopAndBottom(y);
                    views[col][i].setTag(new int[]{col, i});
                }
                data[col][row] = temp;
                views[col][row] = viewTemp;
                views[col][row].setTag(new int[]{col, row});
                views[col][row].offsetTopAndBottom(-(y*(row-row_0)));
                views[col][row].setVisibility(INVISIBLE);
                row_0 = row;
            }else if(row - row_0 < 0){
                y = childWidth;
                int temp = data[col_0][row_0];
                View viewTemp = views[col_0][row_0];
                for(int i = row_0; i > row; i--){
                    data[col][i] = data[col][i-1];
                    views[col][i] = views[col][i-1];
                    views[col][i].offsetTopAndBottom(y);
                    views[col][i].setTag(new int[]{col, i});
                }
                data[col][row] = temp;
                views[col][row] = viewTemp;
                views[col][row].setTag(new int[]{col, row});
                views[col][row].offsetTopAndBottom(-(y*(row_0-row)));
                views[col][row].setVisibility(INVISIBLE);
                row_0 = row;
            }
            views[col][row].setBackground(null);
        }else {
            Log.e("onClick: ", "不能移动");
        }
        if(digitalKlotskiManager.isSuccess(spac, spac)){
//                                Toast.makeText(mContext, "以成功", Toast.LENGTH_SHORT).show();
            setenabled(false);
            if(mDigitalKlotskiChange != null){
                mDigitalKlotskiChange.result(true);
            }
        }else {
//                                Log.e("onClick: ", "未成功");
        }
    }

    public interface DigitalKlotskiChange{
        void result(boolean reslut);
        void onChildViewClick();
    }

    DigitalKlotskiChange mDigitalKlotskiChange;

    public DigitalKlotskiViewGroup setDigitalKlotskiChange(DigitalKlotskiChange mDigitalKlotskiChange) {
        this.mDigitalKlotskiChange = mDigitalKlotskiChange;
        return this;
    }
}
